package com.surfilter.platform.base.service;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;

import com.surfilter.platform.base.exception.SystemException;
import com.surfilter.platform.base.model.ActionPermission;
import com.surfilter.platform.base.model.Constants;
import com.surfilter.platform.base.model.MethodWrap;
import com.surfilter.platform.base.model.ParameterInfo;
import com.surfilter.platform.base.model.ParameterInfoModel;
import com.surfilter.platform.base.model.ParameterMapper;
import com.surfilter.platform.base.model.PermissionMethodType;
import com.surfilter.platform.data.dao.InitDao;
import com.surfilter.platform.data.model.UserModel;

public class ServiceContext {
	
	private static Logger log = Logger.getLogger(ServiceContext.class);
	
	// 模型名称对应的服务名称<ModuleName,ServiceName>
	private static Map<String, String> moduleServiceCache;
	// 模型名与行为名对应的方法<ModuleName_ActionName,Method>
	private static Map<String, MethodWrap> methodCache;

	private static InitDao initDao;

	public static synchronized void init() {
		try {
			initDao = (InitDao) SpringContextUtil.getBean(InitDao.class);
		} catch (Exception e) {
			throw new SystemException("Module DAO Not Found", e);
		}
		try {
			moduleServiceCache = initDao.getAllModulesForCache();
			moduleServiceCache.put(Constants.PLATFORM_MODULE_TAG,
					Constants.SERVICE_PLATFORM);
			methodCache = new HashMap<String, MethodWrap>();
			initAllActionMethod();
		} catch (Exception e) {
			throw new SystemException("Init ServiceContext Error", e);
		}
	}

	public static Set<String> getAllModulesName() {
		return moduleServiceCache.keySet();
	}

	public static Set<String> getModuleActionNameForPermission(
			List<String> modules,List<String> moduleActionNames) {
		Set<String> ret = new HashSet<String>();
		Set<Entry<String, MethodWrap>> set = methodCache.entrySet();
		for (Entry<String, MethodWrap> entry : set) {
			String key = entry.getKey();
			String moduleName = key.split(":")[0];
			MethodWrap wrap = entry.getValue();
			String[] refs = null;
			if (wrap.getType() == PermissionMethodType.NONE) {
				ret.add(key);
				refs = wrap.getRefActions();
			} else if (wrap.getType() == PermissionMethodType.MODULE) {
				if (modules.contains(moduleName)) {
					ret.add(key);
					refs = wrap.getRefActions();
				}
			} else if(moduleActionNames.contains(key)){
				ret.add(key);
				refs = wrap.getRefActions();
			}
			if(refs!=null && refs.length>0){
				for(String ref : refs){
					String refKey = moduleName + ":" + ref;
					if(methodCache.containsKey(refKey)){
						ret.add(refKey);
					}
				}
			}
		}
		if(log.isDebugEnabled())
			log.debug(ret);
		return ret;
	}

	private static synchronized void initAllActionMethod() {
		try {
			if (moduleServiceCache != null && moduleServiceCache.size() > 0) {
				Set<Entry<String, String>> moduleServiceNames = moduleServiceCache
						.entrySet();
				for (Entry<String, String> moduleServiceNameEntry : moduleServiceNames) {
					String moduleName = moduleServiceNameEntry.getKey();
					String serviceName = moduleServiceNameEntry.getValue();
					if (moduleName.equalsIgnoreCase("ROOT"))
						continue;

					Object serviceObject = getServiceObjectByServiceName(serviceName);

					if (serviceObject != null) {
						Class serviceClass = serviceObject.getClass();
						Class targetClass = serviceClass;

						boolean isCglibProxy = false;

						try {
							Method proxyMethod = serviceClass.getMethod(
									"getTargetClass", null);
							if (proxyMethod != null) {
								isCglibProxy = true;
								targetClass = (Class) proxyMethod.invoke(
										serviceObject, null);
							}
						} catch (Exception e) {

						}
						Method[] methods = targetClass.getMethods();
						for (Method methodsrc : methods) {
							ActionPermission acp = methodsrc
									.getAnnotation(ActionPermission.class);
							if (acp != null && acp.actionName() != null
									&& acp.permission() != null) {
								Method method = methodsrc;
								if (isCglibProxy) {
									method = targetClass.getMethod(
											methodsrc.getName(),
											methodsrc.getParameterTypes());
								}
								MethodWrap wrap = new MethodWrap(
										method, acp.actionName(),
										acp.permission(),acp.ref(),targetClass);
								ParameterMapper pma = methodsrc
										.getAnnotation(ParameterMapper.class);
								if (pma != null) {
									ParameterInfo[] pias = pma.value();
									if (pias != null && pias.length > 0) {
										Map<Integer, ParameterInfoModel> map = new HashMap<Integer, ParameterInfoModel>();
										for (ParameterInfo pia : pias) {
											ParameterInfoModel model = new ParameterInfoModel();
											model.setIndex(pia.index());
											model.setMapName(pia.mapName());
											model.setMapType(pia.mapType());
											model.setComponentType(pia
													.componentType());
											map.put(pia.index(), model);
										}
										wrap.setParamInfos(map);
									}
								}
								methodCache.put(
										moduleName + Constants.MODULE_ACTION_SEPERATOR + acp.actionName(),
										wrap);
							}
						}
					}
				}
			}
		} catch (Exception e) {
			throw new SystemException(e);
		}
	}

	private static String getServiceNameByModuleName(String moduleName) {
		return moduleServiceCache.get(moduleName);
	}

	public static Object getServiceObjectByModuleName(String moduleName) {
		try {
			String serviceName = getServiceNameByModuleName(moduleName);
			if (serviceName == null
					|| !SpringContextUtil.containsBean(serviceName)) {
				throw new SystemException("Service[" + serviceName
						+ "] Not Found");
			}
			Object obj = SpringContextUtil.getBean(serviceName);
			return obj;
		} catch (Exception e) {
			throw new SystemException("Get Service Object By Module Exception",
					e);
		}
	}

	private static Object getServiceObjectByServiceName(String serviceName) {
		try {
			if (serviceName == null
					|| !SpringContextUtil.containsBean(serviceName))
				return null;
			Object obj = SpringContextUtil.getBean(serviceName);
			return obj;
		} catch (Exception e) {
			throw new SystemException("Get Service Object By Module Exception",
					e);
		}
	}

	public static MethodWrap getMethodWrapByModuleNameAndActionName(
			String moduleName, String actionName) {
		try {
			MethodWrap methodWrap = methodCache.get(moduleName + Constants.MODULE_ACTION_SEPERATOR
					+ actionName);
			if (methodWrap == null)
				throw new SystemException(actionName + " Not Found In "
						+ moduleName);
			return methodWrap;
		} catch (Exception e) {
			throw new SystemException(e);
		}
	}

	public static Method getMethodByModuleNameAndActionName(String moduleName,
			String actionName) {
		try {
			MethodWrap wrap = getMethodWrapByModuleNameAndActionName(
					moduleName, actionName);
			if (wrap == null)
				throw new SystemException(actionName + " Not Found In "
						+ moduleName);

			return wrap.getMethod();
		} catch (Exception e) {
			throw new SystemException(e);
		}
	}

	public static boolean containsModule(String moduleName) {
		return moduleServiceCache.containsKey(moduleName);
	}

	public static boolean containsAction(String moduleName, String actionName) {
		return methodCache.containsKey(moduleName + Constants.MODULE_ACTION_SEPERATOR + actionName);
	}

	public static void setSessionPermission(HttpSession session,
			UserModel sessionModel) {
		try {
			InitDao initDao = (InitDao) SpringContextUtil
					.getBean(InitDao.class);

			List<String> moduleNames = initDao
					.getUserPerModuleName(sessionModel.getId());

			if (moduleNames != null && moduleNames.size() > 0) {
				Set<String> sessionModuleNames = new HashSet<String>();
				sessionModuleNames.addAll(moduleNames);
				session.setAttribute(Constants.SESSION_MODULES_TAG,
						sessionModuleNames);
				
				List<String> actionNames = initDao
						.getUserPerModuleActionName(sessionModel.getId());

				Set<String> initActions = ServiceContext
						.getModuleActionNameForPermission(moduleNames,actionNames);
				
				session.setAttribute(Constants.SESSION_ACTIONS_TAG, initActions);
			}

		} catch (Exception e) {
			throw new SystemException("Create User Permission Session Error", e);
		}
	}

	public static Map<String, Object> getUserIdAndNameInSession(
			HttpServletRequest request) {
		UserModel user = (UserModel) request.getSession().getAttribute(
				Constants.LOGIN_USER_TAG);
		if(user==null){
			throw new SystemException("User's session is null!");
		}
		Map<String, Object> resp = new HashMap<String,Object>();
		resp.put("id", user.getId());
		resp.put("name", user.getUserName());
		return resp;
	}
	
	public static int getUserIdInSession(
			HttpServletRequest request) {
		UserModel user = (UserModel) request.getSession().getAttribute(
				Constants.LOGIN_USER_TAG);
		if(user==null){
			throw new SystemException("User's session is null!");
		}
		return user.getId();
	}
	
	public static String getUserNameInSession(
			HttpServletRequest request) {
		UserModel user = (UserModel) request.getSession().getAttribute(
				Constants.LOGIN_USER_TAG);
		if(user==null){
			throw new SystemException("User's session is null!");
		}
		return user.getUserName();
	}
}